package com.tepth.appmanageservice.protocol.packets;

import com.tepth.appmanageservice.protocol.Index;
import com.tepth.appmanageservice.protocol.bodys.CommonReply;
import com.tepth.appmanageservice.protocol.bodys.aes.AesReply;
import com.tepth.appmanageservice.protocol.bodys.login.ClientLoginReply;
import com.tepth.appmanageservice.protocol.bodys.ordinaryfile.OperationOrdinaryFile;
import com.tepth.appmanageservice.protocol.bodys.ordinaryfile.OrdinaryFileIssued;
import com.tepth.appmanageservice.protocol.bodys.ordinaryfile.OrdinaryFileRequestReply;
import com.tepth.appmanageservice.protocol.bodys.ordinaryfile.ViewOrdinaryFileList;
import com.tepth.appmanageservice.protocol.bodys.system.ModifyDomainPort;
import com.tepth.appmanageservice.protocol.bodys.system.ModifyHeartbeatFrequency;
import com.tepth.appmanageservice.protocol.bodys.system.PublicKeyRequestReply;
import com.tepth.appmanageservice.protocol.interfaces.IReceive;
import com.tepth.appmanageservice.protocol.interfaces.ISend;
import com.tepth.appmanageservice.tools.ext.ExtToBytes;

public class Packets {
	private Flag begin;
	private Header header;
	private Object body;
	private Check check;
	private Flag end;
	private byte[] bodyBytes;

	private boolean isComplement = false;
	private byte[] datas = null;

	public Flag getBegin() {
		return this.begin;
	}

	public Header getHeader() {
		return this.header;
	}

	public Object getBody() {
		return this.body;
	}

	public Check getCheck() {
		return this.check;
	}

	public Flag getEnd() {
		return this.end;
	}

	public void setComplement() {
		if (this.IsComplement())
			return;

		this.isComplement = true;
	}

	public Packets(Flag begin, Header header, byte[] body, Check check, Flag end) {
		this.begin = begin;
		this.header = header;
		this.bodyBytes = body;
		this.check = check;
		this.end = end;
		if (this.bodyBytes != null)
			this.body = protocol(this.header, this.bodyBytes);
	}

	public Packets(ISend body) {
		this.begin = new Flag();
		this.check = new Check();
		this.end = new Flag();
		this.header = new Header();

		this.body = body;
	}

	private boolean IsComplement() {
		return this.isComplement;
	}

	public <T> T getBodyModel() {
		return (T) this.body;
	}

	public byte[] toBytes() {
		if (this.datas == null)
			refresh();

		return this.datas;
	}

	public static Object protocol(Header header, byte[] body) {
		Object obj;
		switch (header.getId()) {
			case CommonReply.ID:
				obj = instantiationRequest(header, body, new CommonReply());
				break;
			// Login -------------------------------------------------------------------------------------
			case ClientLoginReply.ID:
				obj = instantiationRequest(header, body, new ClientLoginReply());
				break;
			// System ------------------------------------------------------------------------------------
			case ModifyDomainPort.ID:
				obj = instantiationRequest(header, body, new ModifyDomainPort());
				break;
			case ModifyHeartbeatFrequency.ID:
				obj = instantiationRequest(header, body, new ModifyHeartbeatFrequency());
				break;
			case PublicKeyRequestReply.ID:
				obj = instantiationRequest(header, body, new PublicKeyRequestReply());
				break;
			// Aes ---------------------------------------------------------------------------------------
			case AesReply.ID:
				obj = instantiationRequest(header, body, new AesReply());
				break;
			// Ordinary File -----------------------------------------------------------------------------
			case OperationOrdinaryFile.ID:
				obj = instantiationRequest(header, body, new OperationOrdinaryFile());
				break;
			case OrdinaryFileIssued.ID:
				obj = instantiationRequest(header, body, new OrdinaryFileIssued());
				break;
			case OrdinaryFileRequestReply.ID:
				obj = instantiationRequest(header, body, new OrdinaryFileRequestReply());
				break;
			case ViewOrdinaryFileList.ID:
				obj = instantiationRequest(header, body, new ViewOrdinaryFileList());
				break;
			// Sd ----------------------------------------------------------------------------------------

			default:
				obj = new byte[0];
		}

		return obj;
	}

	private static Object instantiationRequest(Header header, byte[] data, IReceive receive) {
		if (header.isSubcontractor())
			return null;
		Index index = new Index();
		receive.setLength(header.getBodyLength());
		receive.Receive(data, index);
		return receive;
	}

	private void refresh() {
		byte[] data = ExtToBytes.generatePacketsData(this.begin, this.header, (ISend) this.body, check, end);
		this.datas = data;
	}

	@Override
	public String toString() {
		try {
			return (this.header == null ? "" : this.header.toString()) + " | " + (this.body == null ? "" : this.body.toString());
		} catch (Exception e) {
			return "";
		}
	}
}